home *** CD-ROM | disk | FTP | other *** search
/ GFX Sensations 1 / Graphic Sensations - Volume 1.iso / tools / amiga / 3d_tools / irit40s.lha / Irit / cagd_lib / bzr2poly.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-30  |  10.8 KB  |  347 lines

  1. /******************************************************************************
  2. * Bzr2Poly.c - Bezier to polygon/polylines conversion routines.              *
  3. *******************************************************************************
  4. * Written by Gershon Elber, Mar. 90.                          *
  5. ******************************************************************************/
  6.  
  7. #include "cagd_loc.h"
  8.  
  9. /*****************************************************************************
  10. * Routine to convert a single bezier surface to set of triangles         *
  11. * approximating it. FineNess is a finess control on result and the bigger it *
  12. * is more triangles may result. a value of 10 is a good start value.         *
  13. * NULL is returned in case of an error, otherwise list of CagdPolygonStruct. *
  14. *****************************************************************************/
  15. CagdPolygonStruct *BzrSrf2Polygons(CagdSrfStruct *Srf, int FineNess,
  16.      CagdBType ComputeNormals, CagdBType FourPerFlat, CagdBType ComputeUV)
  17. {
  18.     int i, j, FineNessU1, FineNessV1, FineNessU, FineNessV, BaseIndex;
  19.     CagdRType *Pt;
  20.     CagdPointType
  21.     PType = Srf -> PType;
  22.     CagdPtStruct PtCenter, *Pt1, *Pt2, *Pt3, *Pt4, *PtMesh, *PtMeshPtr;
  23.     CagdUVStruct UVCenter, *UVMeshPtr,
  24.     *UV1 = NULL,
  25.     *UV2 = NULL,
  26.     *UV3 = NULL,
  27.     *UV4 = NULL,
  28.     *UVMesh = NULL;
  29.     CagdVecStruct NlCenter, *PtNrmlPtr,
  30.     *Nl1 = NULL,
  31.     *Nl2 = NULL,
  32.     *Nl3 = NULL,
  33.     *Nl4 = NULL,
  34.     *PtNrml = NULL;
  35.     CagdPolygonStruct *Poly,
  36.     *PolyHead = NULL;
  37.  
  38.     if (!CAGD_IS_BEZIER_SRF(Srf))
  39.     return NULL;
  40.  
  41.     /* Simple heuristic to estimate how many samples to compute. */
  42.     FineNessU = Srf -> UOrder * FineNess / 10;
  43.     FineNessV = Srf -> VOrder * FineNess / 10;
  44.  
  45.     if (FineNessU < 2)
  46.     FineNessU = 2;
  47.     if (FineNessV < 2)
  48.     FineNessV = 2;
  49.  
  50.     switch (_CagdLin2Poly) {
  51.     case CAGD_REG_POLY_PER_LIN:
  52.         break;
  53.         case CAGD_ONE_POLY_PER_LIN:
  54.         if (Srf -> UOrder == 2)
  55.         FineNessU = 2;
  56.         if (Srf -> VOrder == 2)
  57.         FineNessV = 2;
  58.         break;
  59.         case CAGD_ONE_POLY_PER_COLIN:
  60.         break;
  61.     }
  62.  
  63.     FineNessU1 = FineNessU - 1;
  64.     FineNessV1 = FineNessV - 1;
  65.  
  66.     /* Allocate a mesh to hold all vertices so common vertices need not be   */
  67.     /* Evaluated twice, and evaluate the surface at these mesh points.         */
  68.     PtMeshPtr = PtMesh = (CagdPtStruct *) IritMalloc(FineNessU * FineNessV *
  69.                             sizeof(CagdPtStruct));
  70.  
  71.     for (i = 0; i < FineNessU; i++)
  72.     for (j = 0; j < FineNessV; j++) {
  73.         Pt = BzrSrfEvalAtParam(Srf, ((CagdRType) i) / FineNessU1,
  74.                         ((CagdRType) j) / FineNessV1);
  75.         CagdCoerceToE3(PtMeshPtr -> Pt, &Pt, -1, PType);
  76.         PtMeshPtr++;
  77.     }
  78.  
  79.     if (ComputeNormals) {
  80.     PtNrmlPtr = PtNrml = (CagdVecStruct *)
  81.         IritMalloc(FineNessU * FineNessV * sizeof(CagdVecStruct));
  82.     for (i = 0; i < FineNessU; i++)
  83.         for (j = 0; j < FineNessV; j++) {
  84.         Nl1 = BzrSrfNormal(Srf, ((CagdRType) i) / FineNessU1,
  85.                     ((CagdRType) j) / FineNessV1);
  86.         CAGD_COPY_VECTOR(*PtNrmlPtr, *Nl1);
  87.         PtNrmlPtr++;
  88.         }
  89.     }
  90.  
  91.     if (ComputeUV) {
  92.     UVMeshPtr = UVMesh = (CagdUVStruct *)
  93.         IritMalloc(FineNessU * FineNessV * sizeof(CagdUVStruct));
  94.     for (i = 0; i < FineNessU; i++)
  95.         for (j = 0; j < FineNessV; j++) {
  96.         UVMeshPtr -> UV[0] = ((CagdRType) i) / FineNessU1;
  97.         UVMeshPtr -> UV[1] = ((CagdRType) j) / FineNessU1;
  98.         UVMeshPtr++;
  99.         }
  100.     }
  101.  
  102.     /* Now that we have the mesh, create the polygons. */
  103.     for (i = 0; i < FineNessU1; i++)
  104.     for (j = 0; j < FineNessV1; j++) {
  105.         BaseIndex = i * FineNessV + j;
  106.         Pt1 = &PtMesh[BaseIndex];        /* Cache the four flat corners. */
  107.         Pt2 = &PtMesh[BaseIndex + 1];
  108.         Pt3 = &PtMesh[BaseIndex + FineNessV + 1];
  109.         Pt4 = &PtMesh[BaseIndex + FineNessV];
  110.  
  111.         if (ComputeNormals) {
  112.         Nl1 = &PtNrml[BaseIndex];
  113.         Nl2 = &PtNrml[BaseIndex + 1];
  114.         Nl3 = &PtNrml[BaseIndex + FineNessV + 1];
  115.         Nl4 = &PtNrml[BaseIndex + FineNessV];
  116.         }
  117.         if (ComputeUV) {
  118.         UV1 = &UVMesh[BaseIndex];
  119.         UV2 = &UVMesh[BaseIndex + 1];
  120.         UV3 = &UVMesh[BaseIndex + FineNessV + 1];
  121.         UV4 = &UVMesh[BaseIndex + FineNessV];
  122.         }
  123.  
  124.         if (FourPerFlat) {  /* Eval middle point and create 4 triangles. */
  125.         Pt = BzrSrfEvalAtParam(Srf, (i + 0.5) / FineNessU1,
  126.                             (j + 0.5) / FineNessV1);
  127.         CagdCoerceToE3(PtCenter.Pt, &Pt, -1, PType);
  128.  
  129.         if (ComputeNormals) {
  130.             /* Average the four normals to find the middle one. */
  131.             CAGD_COPY_VECTOR(NlCenter, *Nl1);
  132.             CAGD_ADD_VECTOR(NlCenter, *Nl2);
  133.             CAGD_ADD_VECTOR(NlCenter, *Nl3);
  134.             CAGD_ADD_VECTOR(NlCenter, *Nl4);
  135.             CAGD_NORMALIZE_VECTOR(NlCenter);
  136.         }
  137.  
  138.  
  139.         if (ComputeUV) {
  140.             UVCenter.UV[0] = (UV1 -> UV[0] + UV2 -> UV[0] +
  141.                       UV3 -> UV[0] + UV4 -> UV[0]) / 4.0;
  142.             UVCenter.UV[1] = (UV1 -> UV[1] + UV2 -> UV[1] +
  143.                       UV3 -> UV[1] + UV4 -> UV[1]) / 4.0;
  144.         }
  145.  
  146.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  147.                     Pt1, Pt2, &PtCenter,
  148.                     Nl1, Nl2, &NlCenter,
  149.                     UV1, UV2, &UVCenter);
  150.         CAGD_LIST_PUSH(Poly, PolyHead);
  151.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  152.                     Pt2, Pt3, &PtCenter,
  153.                     Nl2, Nl3, &NlCenter,
  154.                     UV2, UV3, &UVCenter);
  155.         CAGD_LIST_PUSH(Poly, PolyHead);
  156.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  157.                     Pt3, Pt4, &PtCenter,
  158.                     Nl3, Nl4, &NlCenter,
  159.                     UV3, UV4, &UVCenter);
  160.         CAGD_LIST_PUSH(Poly, PolyHead);
  161.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  162.                     Pt4, Pt1, &PtCenter,
  163.                     Nl4, Nl1, &NlCenter,
  164.                     UV4, UV1, &UVCenter);
  165.         CAGD_LIST_PUSH(Poly, PolyHead);
  166.         }
  167.         else {               /* Only two along the diagonal... */
  168.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  169.                     Pt1, Pt2, Pt3,
  170.                     Nl1, Nl2, Nl3,
  171.                     UV1, UV2, UV3);
  172.         CAGD_LIST_PUSH(Poly, PolyHead);
  173.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  174.                     Pt3, Pt4, Pt1,
  175.                     Nl3, Nl4, Nl1,
  176.                     UV3, UV4, UV1);
  177.         CAGD_LIST_PUSH(Poly, PolyHead);
  178.         }
  179.     }
  180.  
  181.     IritFree((VoidPtr) PtMesh);
  182.     if (ComputeNormals)
  183.     IritFree((VoidPtr) PtNrml);
  184.     if (ComputeUV)
  185.     IritFree((VoidPtr) UVMesh);
  186.  
  187.     return PolyHead;
  188. }
  189.  
  190. /*****************************************************************************
  191. * Routine to convert a single bezier surface to NumOfIsoline polyline list   *
  192. * in each param. direction with SamplesPerCurve in each isoparametric curve. *
  193. * Polyline are always E3 of CagdPolylineStruct type.                 *
  194. * Iso parametric curves are sampled equally spaced in parametric space.         *
  195. * NULL is returned in case of an error, otherwise list of CagdPolylineStruct.*
  196. *****************************************************************************/
  197. CagdPolylineStruct *BzrSrf2Polylines(CagdSrfStruct *Srf, int NumOfIsocurves[2],
  198.                              int SamplesPerCurve)
  199. {
  200.     int i;
  201.     CagdRType t;
  202.     CagdCrvStruct *Crv;
  203.     CagdPolylineStruct *PolyList = NULL, *Poly;
  204.  
  205.     if (!CAGD_IS_BEZIER_SRF(Srf))
  206.     return NULL;
  207.  
  208.     /* Make sure requested format is something reasonable. */
  209.     if (SamplesPerCurve < 1)
  210.     SamplesPerCurve = 1;
  211.     if (SamplesPerCurve > CAGD_MAX_BEZIER_CACHE_ORDER)
  212.     SamplesPerCurve = CAGD_MAX_BEZIER_CACHE_ORDER;
  213.     if (NumOfIsocurves[0] < 2)
  214.     NumOfIsocurves[0] = 2;
  215.     if (NumOfIsocurves[1] <= 0)
  216.     NumOfIsocurves[1] = NumOfIsocurves[0];
  217.     else if (NumOfIsocurves[1] < 2)
  218.     NumOfIsocurves[1] = 2;
  219.  
  220.     for (i = 0; i < NumOfIsocurves[0]; i++) {
  221.     t = ((CagdRType) i) / (NumOfIsocurves[0] - 1);
  222.     if (t > 1.0)
  223.         t = 1.0;                     /* In case of round off error. */
  224.  
  225.     Crv = BzrSrfCrvFromSrf(Srf, t, CAGD_CONST_U_DIR);
  226.     Poly = BzrCrv2Polyline(Crv, SamplesPerCurve);
  227.     Poly -> Pnext = PolyList;
  228.     PolyList = Poly;
  229.     CagdCrvFree(Crv);
  230.     }
  231.  
  232.     for (i = 0; i < NumOfIsocurves[1]; i++) {
  233.     t = ((CagdRType) i) / (NumOfIsocurves[1] - 1);
  234.     if (t > 1.0)
  235.         t = 1.0;                     /* In case of round off error. */
  236.  
  237.     Crv = BzrSrfCrvFromSrf(Srf, t, CAGD_CONST_V_DIR);
  238.     Poly = BzrCrv2Polyline(Crv, SamplesPerCurve);
  239.     Poly -> Pnext = PolyList;
  240.     PolyList = Poly;
  241.     CagdCrvFree(Crv);
  242.     }
  243.  
  244.     return PolyList;
  245. }
  246.  
  247. /*****************************************************************************
  248. * Routine to convert a single bezier surface to NumOfIsoline isocurve list   *
  249. * in each param. direction.                             *
  250. * Iso parametric curves are sampled equally spaced in parametric space.         *
  251. * NULL is returned in case of an error, otherwise list of CagdCrvStruct.     *
  252. *****************************************************************************/
  253. CagdCrvStruct *BzrSrf2Curves(CagdSrfStruct *Srf, int NumOfIsocurves[2])
  254. {
  255.     int i;
  256.     CagdRType t;
  257.     CagdCrvStruct *Crv,
  258.     *CrvList = NULL;
  259.  
  260.     if (!CAGD_IS_BEZIER_SRF(Srf))
  261.     return NULL;
  262.  
  263.     /* Make sure requested format is something reasonable. */
  264.     if (NumOfIsocurves[0] < 2)
  265.     NumOfIsocurves[0] = 2;
  266.     if (NumOfIsocurves[1] <= 0)
  267.     NumOfIsocurves[1] = NumOfIsocurves[0];
  268.     else if (NumOfIsocurves[1] < 2)
  269.     NumOfIsocurves[1] = 2;
  270.  
  271.     for (i = 0; i < NumOfIsocurves[0]; i++) {
  272.     t = ((CagdRType) i) / (NumOfIsocurves[0] - 1);
  273.     if (t > 1.0)
  274.         t = 1.0;                     /* In case of round off error. */
  275.  
  276.     Crv = CagdCrvFromSrf(Srf, t, CAGD_CONST_U_DIR);
  277.     Crv -> Pnext = CrvList;
  278.     CrvList = Crv;
  279.     }
  280.  
  281.     for (i = 0; i < NumOfIsocurves[1]; i++) {
  282.     t = ((CagdRType) i) / (NumOfIsocurves[1] - 1);
  283.     if (t > 1.0)
  284.         t = 1.0;                     /* In case of round off error. */
  285.  
  286.     Crv = CagdCrvFromSrf(Srf, t, CAGD_CONST_V_DIR);
  287.     Crv -> Pnext = CrvList;
  288.     CrvList = Crv;
  289.     }
  290.  
  291.     return CrvList;
  292. }
  293.  
  294. /*****************************************************************************
  295. * Routine to convert a single bezier curve to polyline with SamplesPerCurve  *
  296. * samples. Polyline is always E3 of CagdPolylineStruct type.             *
  297. * Curve is sampled equally spaced in parametric space.                 *
  298. * NULL is returned in case of an error, otherwise CagdPolylineStruct.         *
  299. *****************************************************************************/
  300. CagdPolylineStruct *BzrCrv2Polyline(CagdCrvStruct *Crv, int SamplesPerCurve)
  301. {
  302.     int i, j,
  303.     n = 1 << SamplesPerCurve,
  304.     IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv),
  305.     MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
  306.     CagdRType *Polyline[CAGD_MAX_PT_SIZE], Scaler;
  307.     CagdPtStruct *NewPolyline;
  308.     CagdPolylineStruct *P;
  309.  
  310.     if (!CAGD_IS_BEZIER_CRV(Crv))
  311.     return NULL;
  312.  
  313.     /* Make sure requested format is something reasonable. */
  314.     if (SamplesPerCurve < 1)
  315.     SamplesPerCurve = 1;
  316.     if (SamplesPerCurve > CAGD_MAX_BEZIER_CACHE_ORDER)
  317.     SamplesPerCurve = CAGD_MAX_BEZIER_CACHE_ORDER;
  318.  
  319.     P = CagdPolylineNew(n);
  320.     NewPolyline = P -> Polyline;
  321.  
  322.     /* Allocate temporary memory to hold evaluated curve. */
  323.     for (i = 0; i < CAGD_MAX_PT_SIZE; i++)
  324.     Polyline[i] = (CagdRType *) IritMalloc(sizeof(CagdRType) * n);
  325.  
  326.     if (MaxCoord > 3)
  327.     MaxCoord = 3;
  328.  
  329.     BzrCrvEvalToPolyline(Crv, SamplesPerCurve, Polyline);
  330.  
  331.     for (i = n - 1; i >= 0; i--) {              /* Convert to E3 polyline. */
  332.     if (IsNotRational)
  333.         Scaler = 1.0;
  334.     else
  335.         Scaler = Polyline[0][i];
  336.  
  337.     for (j = 0; j < MaxCoord; j++)
  338.         NewPolyline[i].Pt[j] = Polyline[j+1][i] / Scaler;
  339.     for (j = MaxCoord; j < 3; j++)
  340.         NewPolyline[i].Pt[j] = 0.0;
  341.     }
  342.     for (i = 0; i < CAGD_MAX_PT_SIZE; i++)
  343.     IritFree((VoidPtr) Polyline[i]);
  344.  
  345.     return P;
  346. }
  347.